package com.xiashitech.agent.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.xiashitech.agent.grpc.XsConfigClient;
import com.xiashitech.agent.instrumentation.log.XSLevel;
import com.xiashitech.agent.utils.XiashiGrpcUtil;
import com.xiashitech.agent.utils.HttpUtil;
import com.xiashitech.agent.utils.JsonUtil;
import com.xiashitech.interfaces.agent.dto.AgentConfigDTO;
import com.xiashitech.interfaces.agent.dto.SystemInfoDTO;
import com.xiashitech.interfaces.apiservice.dto.AuthFactRequest;
import com.xiashitech.interfaces.apiservice.dto.AuthFactResponse;
import io.opentelemetry.javaagent.bootstrap.internal.InstrumentationConfig;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

public class StartConfig {
    private static final Logger logger = Logger.getLogger(StartConfig.class.getName());
    public static final String agentService = "agentService";

    public static final String systemId = "systemId";
    public static final String nameServer = "nameServer";

    public static final String serverContextPath = "/agentserver";

    // 以下三行为 Grpc 配置，通过 #grpcServer@192.168.0.54:9988 的方式配置来实现
    public static String grpcServer = null;
    public static int grpcPort = Integer.MAX_VALUE;
    public static Boolean isStartGrpc = null;
    public static Boolean isSecureGrpc = null;
    public static Boolean isProxyGrpc = null;
    public static Boolean isGetSystemMsg = Boolean.FALSE;

    public static Boolean isRunSystemMsgJob = Boolean.FALSE;

    private static final Map<String,String> commonParams = new HashMap();

    private static ScheduledExecutorService executorServiceForConfig = Executors.newScheduledThreadPool(1);

    private static ScheduledExecutorService executorServiceForSystem = Executors.newScheduledThreadPool(1);

    public static Map<String,String> getCommonParams() {
        return commonParams;
    }

    public static volatile boolean isGrpcSynced = false;

    public static String getParamValueFromKey(String paramKey) {
        return commonParams.getOrDefault(paramKey.toLowerCase(),"");
    }

    public static void initSync(String agentService) {
        try {
            if(agentService == null || "".equals(agentService)) {
                throw new RuntimeException("config params(agentService) is null,agent startup failure!");
            }
            try {
                String response = null;
                if(StartConfig.isStartGrpc()) { // 启动时，无法从配置信息中判断是否启用GRPC，从参数中判断
                    response = XsConfigClient.getClient().
                            blockingSyncConfig();
                } else {
                    // response = HttpUtil.doPost(agentService + StartConfig.serverContextPath +"/v1/agent/syncConfig");
                    response = HttpUtil.doPost(getAgentServiceRoot() +"/v1/agent/syncConfig");
                }
                if(response != null && !response.isEmpty() && JsonUtil.isJson(response)) {
                    AgentConfigDTO.setConfig(JsonUtil.convertStringToObject(response, AgentConfigDTO.class));
                } else {
                    throw new RuntimeException();
                }
            } catch (Exception e) {
                logger.log(XSLevel.DEBUG, "The Agent failed to obtain parameter information from Agentservice.");
            }
        } catch (Exception e) {
            StartConfig.throwableStackPrinter(e);
        } finally {
            executorServiceForConfig.scheduleAtFixedRate(() -> {
                try {
                    System.out.println("executorServiceForConfig: " + XiashiGrpcUtil.useGrpc() + ", " + isGrpcSynced);
                    if(XiashiGrpcUtil.useGrpc()) {
                        if(!isGrpcSynced) {
                            XsConfigClient.getClient().grpcSyncConfig();
                            isGrpcSynced = true;
                            // 采用 Grpc 方式，使用服务端推送，无需定时拉取，
                            // 但这里如果把这个s chedule 关闭，通过配置从 grpc 换回 dopost 会不更新 dopost
                            // executorServiceForConfig.shutdown();
                        }
                    } else {
                        isGrpcSynced = false; // 用于再次切会 grpc 时，能够发起恢复通道的请求
                        // String response = HttpUtil.doPost(agentService + StartConfig.serverContextPath + "/v1/agent/syncConfig");
                        String response = HttpUtil.doPost(getAgentServiceRoot() + "/v1/agent/syncConfig");
                        if (response != null && !response.isEmpty() && JsonUtil.isJson(response)) {
                            AgentConfigDTO.setConfig(JsonUtil.convertStringToObject(response, AgentConfigDTO.class));
                        }
                    }
                } catch (Exception e) {
                    logger.log(XSLevel.DEBUG, "The Agent failed to obtain parameter information from Agentservice.");
                }
            },1,1, TimeUnit.MINUTES);
        }
    }

    public static void initCommonParams(String commonParams) {
        if(commonParams != null) {
            String[] params = commonParams.split("#");
            for (String param : params) {
                String[] kvs = param.split("@");
                StartConfig.getCommonParams().put(kvs[0].toLowerCase(),kvs[1].toLowerCase());
            }
        }
    }

    public static void initEnvVar() {
        String systemId = InstrumentationConfig.get().getString("xs.bootstrap.systemid");
        String agentService = InstrumentationConfig.get().getString("xs.bootstrap.agentservice");
        String grpcServer = InstrumentationConfig.get().getString("xs.bootstrap.grpcserver");
        String nameServer = InstrumentationConfig.get().getString("xs.bootstrap.nameserver");
        String lbMode = InstrumentationConfig.get().getString("xs.bootstrap.lbmode");
        if(systemId != null) {
            StartConfig.getCommonParams().put("systemid",systemId.toLowerCase());
        }
        if(agentService != null) {
            StartConfig.getCommonParams().put("agentservice",agentService.toLowerCase());
        }
        if(grpcServer != null) {
            StartConfig.getCommonParams().put("grpcserver",grpcServer.toLowerCase());
        }
        if(nameServer != null) {
            StartConfig.getCommonParams().put("nameserver",nameServer.toLowerCase());
        }
        if(lbMode != null) {
            StartConfig.getCommonParams().put("lbmode",lbMode.toLowerCase());
        }
    }

    public static void initSystemInfo(String agentService) {
        if(agentService == null || "".equals(agentService)) {
            throw new RuntimeException("config params(agentService) is null,agent startup failure!");
        }
        String systemId = StartConfig.getParamValueFromKey(StartConfig.systemId);
        if(systemId == null || "".equals(systemId)) {
            throw new RuntimeException("config params(systemId) is null,agent startup failure!");
        }
        try {
            AgentConfigDTO agentConfig = AgentConfigDTO.getConfig();
            if(agentConfig == null) {
                throw new RuntimeException("config params is null,agent startup failure!");
            }
            Map<String,String> systemAppCode = agentConfig.getSystemAppCode();
            if(systemAppCode == null) {
                throw new RuntimeException("config params(appCode) is null,agent startup failure!");
            }
            String appCode = systemAppCode.get(StartConfig.getParamValueFromKey(StartConfig.systemId));
            if(appCode == null || "".equals(appCode)) {
                throw new RuntimeException("config params(appCode) is null,agent startup failure!");
            }
            AuthFactRequest authFactRequest = new AuthFactRequest();
            authFactRequest.setSystemId(systemId);
            authFactRequest.setAppCode(appCode);
            authFactRequest.setSign(AgentConfigDTO.getConfig().getSystemSign().get(StartConfig.getParamValueFromKey(StartConfig.systemId)));
            ObjectMapper objectMapper = new ObjectMapper();
            String param = objectMapper.writeValueAsString(authFactRequest);
            String response = null;
            if(XiashiGrpcUtil.useGrpc()) {
                response = XsConfigClient.getClient().grpcInitSystemInfo(authFactRequest);
            } else {
                // response = HttpUtil.doPost(agentService + StartConfig.serverContextPath + "/v1/agent/getSystemInfo", param, "application/json;charset=UTF-8");
                response = HttpUtil.doPost(getAgentServiceRoot() + "/v1/agent/getSystemInfo", param, "application/json;charset=UTF-8");
            }
            if(response != null && !response.isEmpty() && JsonUtil.isJson(response)) {
                AuthFactResponse authFactResponse = JsonUtil.convertStringToObject(response, AuthFactResponse.class);
                if(authFactResponse != null) {
                    SystemInfoDTO.setConfig(authFactResponse.getSystemInfoDTO());
                    isGetSystemMsg = Boolean.TRUE;
                }
            } else {
                throw new RuntimeException();
            }
        } catch (Exception e) {
            logger.log(XSLevel.DEBUG, "The Agent failed to obtain parameter information from Agentservice.");
        } finally {
            if(!isGetSystemMsg && !isRunSystemMsgJob) {
                isRunSystemMsgJob = Boolean.TRUE;
                executorServiceForSystem.scheduleAtFixedRate(() -> {
                    if(!isGetSystemMsg) {
                        initSystemInfo(agentService);
                    } else {
                        executorServiceForSystem.shutdown();
                    }
                },1,1, TimeUnit.MINUTES);
            }
        }
    }

    public static void throwableStackPrinter(Throwable e) {
        if(InstrumentationConfig.get().getBoolean("xs.debug", false))
            e.printStackTrace();
    }

    public static String getGrpcServer() {
        if(grpcServer == null) {
            initGrpcParam();
        }
        return grpcServer;
    }
    public static int getGrpcPort() {
        if(grpcPort == Integer.MAX_VALUE) {
            initGrpcParam();
        }
        return grpcPort;
    }
    public static Boolean isStartGrpc() {
        if(isStartGrpc == null) {
            initGrpcParam();
        }
        return isStartGrpc;
    }
    public static Boolean isSecureGrpc() {
        if(isSecureGrpc == null) {
            initGrpcParam();
        }
        return isSecureGrpc;
    }
    public static Boolean isProxyGrpc() {
        if(isProxyGrpc == null) {
            initGrpcParam();
        }
        return isProxyGrpc;
    }
    private static void initGrpcParam() {
//        grpcServer = "";
//        isStartGrpc = Boolean.FALSE;
//        grpcPort = 0;
//        String grpcServerCfg = commonParams.get("grpcServer".toLowerCase());
//        System.out.println("grpcServer: " + grpcServerCfg);
//        if (grpcServerCfg != null) {
//            isStartGrpc = Boolean.TRUE;
//            String[] svrport = grpcServerCfg.split(":");
//            System.out.println("grpcServer svrport: " + svrport);
//            if (svrport.length == 2) {
//                grpcServer = svrport[0];
//                grpcPort = Integer.parseInt(svrport[1]);
//            }
//        }
        /**
         * 1、""
         * 2、"bjrm.ytmedia.cn"
         * 3、"192.168.0.229:9988","http://192.168.0.229","proxy://192.168.0.229","https://192.168.0.229"
         * 4、"http://192.168.0.229:9988","proxy://192.168.0.229:9988","https://192.168.0.229:9988"
         */
        isProxyGrpc = Boolean.TRUE;
        String grpcServerCfg = commonParams.get("grpcServer".toLowerCase());
        if (grpcServerCfg == null || grpcServerCfg.isEmpty()) {
            isStartGrpc = Boolean.FALSE;
            // isProxyGrpc = Boolean.TRUE;
            isSecureGrpc = Boolean.FALSE;
            grpcServer = "";
            grpcPort = 0;
        } else {
            String[] grpcPart = grpcServerCfg.split(":");
            if (grpcPart.length == 1) { // 只有一个域名，默认是 HTTPS 方式
                isStartGrpc = Boolean.TRUE;
                // isProxyGrpc = Boolean.TRUE;
                isSecureGrpc = Boolean.TRUE;
                grpcServer = grpcPart[0];
                grpcPort = 443;
            } else if (grpcPart.length == 2) { //  只能是 http(s)://www.xrxs.com 或者是 www.xrxs.com:9988
                if ("http".equalsIgnoreCase(grpcPart[0])) {
                    isStartGrpc = Boolean.TRUE;
                    isProxyGrpc = Boolean.FALSE;
                    isSecureGrpc = Boolean.FALSE;
                    grpcServer = grpcPart[1].substring(2);
                    grpcPort = 80;
                } else if ("proxy".equalsIgnoreCase(grpcPart[0])) {
                    isStartGrpc = Boolean.TRUE;
                    // isProxyGrpc = Boolean.TRUE;
                    isSecureGrpc = Boolean.FALSE;
                    grpcServer = grpcPart[1].substring(2);
                    grpcPort = 80;
                } else if ("https".equalsIgnoreCase(grpcPart[0])) {
                    isStartGrpc = Boolean.TRUE;
                    // isProxyGrpc = Boolean.TRUE;
                    isSecureGrpc = Boolean.TRUE;
                    grpcServer = grpcPart[1].substring(2);
                    grpcPort = 443;
                } else {
                    // 只是域名和端口
                    isStartGrpc = Boolean.TRUE;
                    // isProxyGrpc = Boolean.TRUE;
                    isSecureGrpc = Boolean.FALSE;
                    grpcServer = grpcPart[0];
                    grpcPort = Integer.parseInt(grpcPart[1]);
                }
            } else if (grpcPart.length == 3) { //  只能是 http(s)://www.xrxs.com 或者是 www.xrxs.com:9988
                isStartGrpc = Boolean.TRUE;
                if ("http".equalsIgnoreCase(grpcPart[0])) {
                    isSecureGrpc = Boolean.FALSE;
                    isProxyGrpc = Boolean.FALSE;
                } else if ("proxy".equalsIgnoreCase(grpcPart[0])) {
                    isSecureGrpc = Boolean.FALSE;
                    // isProxyGrpc = Boolean.TRUE;
                } else if ("https".equalsIgnoreCase(grpcPart[0])) {
                    // isProxyGrpc = Boolean.TRUE;
                    isSecureGrpc = Boolean.TRUE;
                }
                grpcServer = grpcPart[1].substring(2);
                grpcPort = Integer.parseInt(grpcPart[2]);
            } else {
                System.out.println("grpcServer is: " + grpcServerCfg + ", format error");
                return;
            }
        }
        System.out.println("grpcServer is: " + grpcServerCfg + ", isStartGrpc: " + isStartGrpc + ", isProxy: " + isProxyGrpc + ", isSecureGrpc: " + isSecureGrpc + ", server: " + grpcServer + ", port: " + grpcPort);
    }

    public static String getAgentServiceRoot() {
        String agentServiceUrl = getParamValueFromKey(agentService);
        if(agentServiceUrl.indexOf("/") > 0) {
            System.out.println("getAgentServiceRoot called A agentService: " + agentServiceUrl);
            return agentServiceUrl;
        }
        System.out.println("getAgentServiceRoot called B agentService: " + (agentServiceUrl + serverContextPath));
        return agentServiceUrl + serverContextPath;
    }
}
